$(function() { new Controller(); });

/**
 * @constructor
 */
function Controller()
{
	"use strict";

	/** @type {UrlObject} */
	var _url = new UrlObject();
	/** @type {View} */
	var _view = new View(_url);
	/** @type {Flickr} */
	var _flickr = new Flickr(Enum.flickr.key, Enum.flickr.secret);
	/**
	 * Size URLs to load from Flickr
	 * @type {Array.<Enum.size>}
	 */
	var _photoSizes = [
		Enum.filmstrip.thumbSize,
		Enum.map.thumbSize,
		Enum.size.large1024,
		Enum.size.large1600,
		Enum.size.large2048,
		Enum.size.original
	];

	function init()
	{
		_view.map.handleEnlarged = _view.mapEnlarged;
		_view.map.handleClosed = _view.mapClosed;
		_view.map.handleMarkerClick = handleMapMarkerClick;
		_view.menu.showSet = showSet;
		_view.slideshow.next = nextPhoto;
		_view.toolbar.nextPhoto = nextPhoto;
		_view.toolbar.previousPhoto = previousPhoto;
		_view.strip.handlePhotoClick = handleFilmstripClick;

		Photo.prototype.loadExif = loadExif;

		if (_url.hasSet())
		{
			// show set and load menu
			showSet(_url.setID, _url.photoID, loadMenu);
		}
		else if (_url.hasPhotoOnly())
		{
			// find set that contains the photo then load table of contents
			_flickr.getContext(_url.photoID, function(sets)
			{
				_url.setID = sets[0].id;
				showSet(_url.setID, _url.photoID, loadMenu);
			});
		}
		else
		{
			// show shuffled set of favorites while table of contents is loaded and shown
			_view.prepareSlideshow();

			/** @type {Set} */
			var set = new Set({ id: _url.setID, title: Enum.title });

			set.load(_flickr, _photoSizes, function()
			{
				_view.slideshow.active = true;   // will start slideshow after first image is loaded
				set.shufflePhotos().beginPhotoDownload();
				Session.updateSet(set);
				_url.normalize(/\/$/);
				_view.setChanged(function() { loadMenu(true); });
			});
		}
	}

//- Filmstrip handlers --------------------------------------------------------

	/**
	 *
	 * @param {Photo} photo
	 */
	function handleFilmstripClick(photo)
	{
		Session.updatePhoto(photo);
		_view.photo.show();
		_view.slideshow.stop();
	}

//- Map handlers --------------------------------------------------------------

	/**
	 * Respond to click on map marker
	 * @param {Photo} photo
	 */
	function handleMapMarkerClick(photo)
	{
		photo.closeInfoWindow();
		_view.map.close();
		Session.updatePhoto(photo);
		_view.photo.show();
	}

//- Navigation handlers -------------------------------------------------------

	/**
	 * Show the next photo
	 */
	function nextPhoto() { if (Session.set.nextPhoto()) { showPhoto(); } }

	/**
	 * Show the previous photo
	 */
	function previousPhoto() { if (Session.set.previousPhoto()) { showPhoto(); } }

	/**
	 * Set and show the current photo
	 */
	function showPhoto() { Session.updatePhoto(); _view.photo.show(); }

//- Loaders -------------------------------------------------------------------

	/**
	 * @param {Function(Photo)} [callback]
	 * @this {Photo}
	 */
	function loadExif(callback)
	{
		/** @type {Photo} */
		var p = this;

		_flickr.getEXIF(p.id, function(r)
		{
			p.exif = new Exif(r);
			if (callback) { callback(p); }
		});
	}

	/**
	 * @param {Boolean} [andShow = false]
	 * Load the root collection for display as table of contents
	 */
	function loadMenu(andShow)
	{
		_flickr.getCollection(function(r)
		{
			// preview set is loaded before tree
			Session.tree = new Tree(r, Session.set);
			_view.menu.setup();
			if (andShow) { _view.menu.show(); }
		});
	}

	/**
	 * Load photo set either from flickr service or tree cache
	 * @param {String} id Flickr set ID
	 * @param {Function(SetObject)} callback Method to call when set has loaded
	 */
	function loadSet(id, callback)
	{
		var set = (Session.tree) ? Session.tree.setWithID(id) : new Set({id: id});

		if (set && !set.loaded)
		{
			set.load(_flickr, _photoSizes, callback);
		}
		else
		{
			callback(set);
		}
	}

	/**
	 * Build HTML and prepare animations for a flickr set
	 * @param {String} id Flickr set ID
	 * @param {String} [photoID] Optional photo ID to display initially
	 * @param {Function} [callback] Method called when first photo-of-set image has downloaded
	 */
	function showSet(id, photoID, callback)
	{
		_view.setChanging();

		loadSet(id, function(s)
		{
			Session.updateSet(s);
			Session.set.beginPhotoDownload(photoID);
			_url.update();
			_view.setChanged(callback);
		});
	}

	init();
}